﻿#region Copyright Info

// 
// Majesty of Omega - The next evolution of macro management space strategy
// 
// Copyright 2007-2009 André Claaßen
// 
// This file is protected by the terms and conditions of the
// Microsoft Community License (Ms-CL 1.1), a copy of which should
// have been distributed along with this software. If not,
// you may find the license information at the following URL:
// 
// http://www.microsoft.com/resources/sharedsource/licensingbasics/communitylicense.mspx

#endregion

#region

using System;
using System.Windows;
using System.Windows.Threading;
using DesignByContract;
using Majesty_of_Omega.Logic.GameConfiguration;

#endregion

namespace Majesty_of_Omega.GUI.Pages.Parts
{
    /// <summary>
    /// The SavedGamesGridPart encapsulate a grid of SaveGame entries. 
    /// </summary>
    /// <remarks>
    /// The grid is animated like the E3 Demo of the Master of Orion Alpha Build at the E3 Consumer Show in 2001.
    /// </remarks>
    public partial class SavedGamesGridPart
    {
        #region GridTypeEnum enum

        /// <summary>
        /// Type of the Grid: Load or Save a gmae
        /// </summary>
        public enum GridTypeEnum
        {
            /// <summary>
            /// Load Game. The user choose a game
            /// </summary>
            LoadGame,
            /// <summary>
            /// Save Game. The first entry creates a new save game
            /// </summary>
            SaveGame
        }

        #endregion

        /// <summary>
        /// DependencyProperty for the type of the grid.
        /// </summary>
        public static readonly DependencyProperty GridTypeProperty =
            DependencyProperty.Register("GridType", typeof (GridTypeEnum), typeof (SavedGamesGridPart),
                                        new UIPropertyMetadata(GridTypeEnum.LoadGame));

        /// <summary>
        /// this variable is for the paging function in this grid.
        /// </summary>
        private int _firstGamePosInList;

        /// <summary>
        /// Initialize a new instance of  <see cref="SavedGamesGridPart"/> class.
        /// </summary>
        public SavedGamesGridPart()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Number of game entrys per page
        /// </summary>
        private int NumberOfGamesPerPage
        {
            get { return LayoutRoot.Rows*LayoutRoot.Columns; }
        }

        /// <summary>
        /// Gets or sets the type of the grid.
        /// </summary>
        /// <value>The type of the grid.</value>
        public GridTypeEnum GridType
        {
            get { return (GridTypeEnum) GetValue(GridTypeProperty); }
            set { SetValue(GridTypeProperty, value); }
        }

        /// <summary>
        /// Gets my game manager out of the DataContext of this control.
        /// </summary>
        /// <value>My game manager.</value>
        private SaveGameManager MySaveGameManager
        {
            get { return (SaveGameManager) DataContext; }
        }

        ///<summary>
        ///Invoked whenever the effective value of any dependency property on this <see cref="T:System.Windows.FrameworkElement" /> has been updated. The specific dependency property that changed is reported in the arguments parameter. Overrides <see cref="M:System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)" />.
        ///</summary>
        ///<param name="e">The event data that describes the property that changed, as well as old and new values.</param>
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property.Name != "DataContext") return;
            if (e.NewValue == null)
            {
                LayoutRoot.Children.Clear();
            }
            else
            {
                FillListWithGames((SaveGameManager) e.NewValue);
            }
        }


        /// <summary>
        /// Fills the list with games. 
        /// </summary>
        /// <remarks>
        /// This function supports paging.
        /// Todo: This function is horrible written and should be refactored
        /// </remarks>
        /// <param name="saveGameManager">The game manager.</param>
        private void FillListWithGames(SaveGameManager saveGameManager)
        {
            var indexOfGame = _firstGamePosInList;
            var indexOfEntrySlot = 0;
            var bPrevPageButton = indexOfGame != 0;
            var numberOfGamesPerPage = NumberOfGamesPerPage;

            LayoutRoot.Children.Clear();
            if (bPrevPageButton)
            {
                AddEntryPart(ref indexOfEntrySlot, SaveGameEntryPart.SaveGameEntryType.PrevPage, null);
                numberOfGamesPerPage--;
            }

            var iLastPositionOfFilledEntry = Math.Min(saveGameManager.LastGamesInMooGameFolder.Count,
                                                      _firstGamePosInList + numberOfGamesPerPage);
            var iLastVisiblePosition = _firstGamePosInList + numberOfGamesPerPage;
            var bNextPageButton = saveGameManager.LastGamesInMooGameFolder.Count >= iLastVisiblePosition;
            if (bNextPageButton) iLastPositionOfFilledEntry--;

            while (indexOfGame < iLastPositionOfFilledEntry)
            {
                AddEntryPart(ref indexOfEntrySlot, SaveGameEntryPart.SaveGameEntryType.FilledGameEntry,
                             saveGameManager.LastGamesInMooGameFolder[indexOfGame]);
                indexOfGame++;
            }

            if (bNextPageButton)
            {
                AddEntryPart(ref indexOfEntrySlot, SaveGameEntryPart.SaveGameEntryType.NextPage, null);
            }
            else
            {
                while (indexOfGame < iLastVisiblePosition)
                {
                    AddEntryPart(ref indexOfEntrySlot, SaveGameEntryPart.SaveGameEntryType.EmptyGameEntry, null);
                    indexOfGame++;
                }
            }
        }

        /// <summary>
        /// Adds a new entry part and connects with all events
        /// </summary>
        /// <param name="indexOfEntrySlot">The i position.</param>
        /// <param name="entryType">Type of the entry.</param>
        /// <param name="saveGameInfo">The save game info.</param>
        private void AddEntryPart(ref int indexOfEntrySlot, SaveGameEntryPart.SaveGameEntryType entryType,
                                  SaveGameManager.SaveGameInfo saveGameInfo)
        {
            var entryPart = new SaveGameEntryPart(entryType, indexOfEntrySlot, saveGameInfo);
            entryPart.NextPage += EntryPart_OnNextPage;
            entryPart.PrevPage += EntryPart_OnPrevPage;
            LayoutRoot.Children.Add(entryPart);
            indexOfEntrySlot++;
        }

        /// <summary>
        /// Handles the OnPrevPage event of the EntryPart control. Switch to the previous page of games
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void EntryPart_OnPrevPage(object sender, EventArgs e)
        {
            Require.IsNotNull(DataContext);
            Require.IsTrue(DataContext is SaveGameManager);

            _firstGamePosInList -= NumberOfGamesPerPage - 1;
            if (_firstGamePosInList < 0)
                _firstGamePosInList = 0;
            ChangePageWithAnimation();
        }

        /// <summary>
        /// Handles the OnNextPage event of the EntryPart control. Switch to the next page of games
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void EntryPart_OnNextPage(object sender, EventArgs e)
        {
            Require.IsNotNull(DataContext);
            Require.IsTrue(DataContext is SaveGameManager);

            _firstGamePosInList += _firstGamePosInList == 0 ? NumberOfGamesPerPage - 1 : NumberOfGamesPerPage - 2;
            StartUnloadAnimation();
            ChangePageWithAnimation();
        }

        /// <summary>
        /// Changes the Page with the unload animation.
        /// </summary>
        private void ChangePageWithAnimation()
        {
            StartUnloadAnimation();
            var dispatcherTimer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 2)};
            dispatcherTimer.Tick += delegate
                                        {
                                            FillListWithGames((SaveGameManager) DataContext);
                                            dispatcherTimer.Stop();
                                        };
            dispatcherTimer.Start();
        }

        /// <summary>
        /// Starts the unload animation.
        /// </summary>
        public void StartUnloadAnimation()
        {
            foreach (SaveGameEntryPart savedGamesEntryPart in LayoutRoot.Children)
            {
                savedGamesEntryPart.StartUnloadAnimation();
            }
        }

        /// <summary>
        /// Duration of the Animation
        /// </summary>
        /// <returns>2 seconds</returns>
        public TimeSpan Duration()
        {
            return new TimeSpan(0, 0, 0, 2);
        }

        /// <summary>
        /// Refreshes the content of the current page. This function will be called, when the user saves a new game.
        /// </summary>
        public void RefreshContent()
        {
            FillListWithGames(MySaveGameManager);
        }
    }
}